<template>
  <div class="port-scanner-tool">
    <div class="tool-header">
      <h1>端口扫描器</h1>
      <p>扫描指定IP的开放端口</p>
    </div>

    <div class="tool-container">
      <el-row :gutter="20">
        <!-- 扫描主体 -->
        <el-col :span="16">
          <div class="scanner-section">
            <!-- 扫描配置 -->
            <div class="scanner-config">
              <h3>端口扫描配置</h3>
              <div class="config-inputs">
                <div class="input-group">
                  <label>目标IP：</label>
                  <el-input
                    v-model="targetIP"
                    placeholder="请输入IP地址或域名"
                    size="large"
                    @keyup.enter="startScan"
                  >
                    <template #prepend>
                      <el-icon><Link /></el-icon>
                    </template>
                  </el-input>
                </div>
                
                <div class="scan-options">
                  <div class="option-group">
                    <label>扫描类型：</label>
                    <el-select v-model="scanType" @change="onScanTypeChange" size="large">
                      <el-option label="快速扫描" value="quick" />
                      <el-option label="标准扫描" value="standard" />
                      <el-option label="全面扫描" value="full" />
                      <el-option label="自定义端口" value="custom" />
                    </el-select>
                  </div>
                  
                  <div class="option-group" v-if="scanType === 'custom'">
                    <label>端口范围：</label>
                    <el-input
                      v-model="customPorts"
                      placeholder="如：80,443,8080-8090"
                      size="large"
                    />
                  </div>
                  
                  <div class="option-group">
                    <label>超时时间：</label>
                    <el-select v-model="timeout" size="large">
                      <el-option label="1秒" :value="1000" />
                      <el-option label="3秒" :value="3000" />
                      <el-option label="5秒" :value="5000" />
                    </el-select>
                  </div>
                </div>
                
                <div class="scan-actions">
                  <el-button @click="startScan" type="primary" size="large" :loading="isScanning" :disabled="!targetIP.trim()">
                    <el-icon><Search /></el-icon>
                    开始扫描
                  </el-button>
                  <el-button @click="stopScan" size="large" :disabled="!isScanning">
                    停止扫描
                  </el-button>
                  <el-button @click="clearResults" size="large">
                    清空结果
                  </el-button>
                </div>
              </div>
            </div>
            
            <!-- 扫描进度 -->
            <div class="scan-progress" v-if="isScanning">
              <h4>扫描进度</h4>
              <el-progress :percentage="scanProgress" :status="scanProgress === 100 ? 'success' : ''" />
              <div class="progress-info">
                <span>{{ scanStatus }}</span>
                <span>{{ scanProgress }}% ({{ currentPort }}/{{ totalPorts }})</span>
              </div>
            </div>
            
            <!-- 扫描结果 -->
            <div class="scan-results" v-if="scanResults.length > 0">
              <h3>扫描结果</h3>
              <div class="results-summary">
                <div class="summary-item">
                  <div class="summary-label">目标IP</div>
                  <div class="summary-value">{{ targetIP }}</div>
                </div>
                <div class="summary-item">
                  <div class="summary-label">扫描端口</div>
                  <div class="summary-value">{{ totalPorts }} 个</div>
                </div>
                <div class="summary-item">
                  <div class="summary-label">开放端口</div>
                  <div class="summary-value">{{ openPortsCount }} 个</div>
                </div>
                <div class="summary-item">
                  <div class="summary-label">扫描时间</div>
                  <div class="summary-value">{{ scanDuration }}s</div>
                </div>
              </div>
              
              <div class="ports-table">
                <div class="table-header">
                  <div class="header-cell">端口</div>
                  <div class="header-cell">状态</div>
                  <div class="header-cell">服务</div>
                  <div class="header-cell">协议</div>
                  <div class="header-cell">响应时间</div>
                </div>
                <div 
                  v-for="result in scanResults" 
                  :key="result.port"
                  class="table-row"
                  :class="{ 'open': result.status === 'open' }"
                >
                  <div class="cell port-cell">{{ result.port }}</div>
                  <div class="cell status-cell">
                    <el-tag :type="result.status === 'open' ? 'success' : 'info'" size="small">
                      {{ result.status === 'open' ? '开放' : '关闭' }}
                    </el-tag>
                  </div>
                  <div class="cell service-cell">{{ result.service }}</div>
                  <div class="cell protocol-cell">{{ result.protocol }}</div>
                  <div class="cell time-cell">{{ result.responseTime }}ms</div>
                </div>
              </div>
            </div>
            
            <!-- 扫描历史 -->
            <div class="scan-history">
              <h3>扫描历史</h3>
              <div class="history-list">
                <div 
                  v-for="(item, index) in scanHistory" 
                  :key="index"
                  class="history-item"
                  @click="loadFromHistory(item)"
                >
                  <div class="history-ip">{{ item.ip }}</div>
                  <div class="history-info">
                    <span class="history-ports">{{ item.totalPorts }} 端口</span>
                    <span class="history-open">{{ item.openPorts }} 开放</span>
                    <span class="history-time">{{ item.date }}</span>
                  </div>
                </div>
                <div v-if="scanHistory.length === 0" class="empty-history">
                  暂无扫描历史
                </div>
              </div>
            </div>
          </div>
        </el-col>

        <!-- 工具和说明 -->
        <el-col :span="8">
          <div class="tools-section">
            <div class="section-header">
              <h3>常用端口</h3>
            </div>
            
            <div class="common-ports">
              <div 
                v-for="port in commonPorts" 
                :key="port.port"
                class="port-item"
                @click="setPort(port.port)"
              >
                <div class="port-number">{{ port.port }}</div>
                <div class="port-info">
                  <div class="port-service">{{ port.service }}</div>
                  <div class="port-description">{{ port.description }}</div>
                </div>
              </div>
            </div>
          </div>
          
          <div class="help-section">
            <el-card>
              <template #header>
                <div class="card-header">
                  <span>使用说明</span>
                </div>
              </template>
              
              <div class="help-content">
                <h4>扫描类型：</h4>
                <ul>
                  <li><strong>快速扫描：</strong> 扫描常用端口 (1-1000)</li>
                  <li><strong>标准扫描：</strong> 扫描标准端口 (1-10000)</li>
                  <li><strong>全面扫描：</strong> 扫描所有端口 (1-65535)</li>
                  <li><strong>自定义端口：</strong> 指定特定端口范围</li>
                </ul>
                
                <h4>端口状态：</h4>
                <ul>
                  <li><strong>开放：</strong> 端口可访问，有服务运行</li>
                  <li><strong>关闭：</strong> 端口不可访问</li>
                  <li><strong>过滤：</strong> 端口被防火墙过滤</li>
                </ul>
                
                <h4>注意事项：</h4>
                <div class="warning">
                  <p>⚠️ 仅用于合法的安全测试</p>
                  <p>⚠️ 请勿扫描他人服务器</p>
                  <p>⚠️ 扫描可能被目标系统记录</p>
                </div>
              </div>
            </el-card>
          </div>
        </el-col>
      </el-row>
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'
import { ElMessage } from 'element-plus'
import { Link, Search } from '@element-plus/icons-vue'

const targetIP = ref('')
const scanType = ref('quick')
const customPorts = ref('')
const timeout = ref(3000)
const isScanning = ref(false)
const scanProgress = ref(0)
const scanStatus = ref('')
const currentPort = ref(0)
const totalPorts = ref(0)
const scanResults = ref([])
const scanHistory = ref([])
const scanStartTime = ref(0)

const commonPorts = [
  { port: 21, service: 'FTP', description: '文件传输协议' },
  { port: 22, service: 'SSH', description: '安全外壳协议' },
  { port: 23, service: 'Telnet', description: '远程登录协议' },
  { port: 25, service: 'SMTP', description: '邮件传输协议' },
  { port: 53, service: 'DNS', description: '域名解析服务' },
  { port: 80, service: 'HTTP', description: '网页服务' },
  { port: 110, service: 'POP3', description: '邮件接收协议' },
  { port: 143, service: 'IMAP', description: '邮件访问协议' },
  { port: 443, service: 'HTTPS', description: '安全网页服务' },
  { port: 993, service: 'IMAPS', description: '安全邮件访问' },
  { port: 995, service: 'POP3S', description: '安全邮件接收' },
  { port: 3389, service: 'RDP', description: '远程桌面协议' }
]

const openPortsCount = computed(() => {
  return scanResults.value.filter(result => result.status === 'open').length
})

const scanDuration = computed(() => {
  if (scanStartTime.value === 0) return 0
  return ((Date.now() - scanStartTime.value) / 1000).toFixed(1)
})

const validateIP = (ip) => {
  const ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
  const domainRegex = /^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9](?:\.[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])*$/
  
  return ipv4Regex.test(ip) || domainRegex.test(ip)
}

const getPortRange = () => {
  switch (scanType.value) {
    case 'quick':
      return Array.from({ length: 1000 }, (_, i) => i + 1)
    case 'standard':
      return Array.from({ length: 10000 }, (_, i) => i + 1)
    case 'full':
      return Array.from({ length: 65535 }, (_, i) => i + 1)
    case 'custom':
      return parseCustomPorts()
    default:
      return []
  }
}

const parseCustomPorts = () => {
  if (!customPorts.value.trim()) return []
  
  const ports = []
  const parts = customPorts.value.split(',')
  
  for (const part of parts) {
    const trimmed = part.trim()
    if (trimmed.includes('-')) {
      const [start, end] = trimmed.split('-').map(p => parseInt(p.trim()))
      if (start && end && start <= end) {
        for (let i = start; i <= end; i++) {
          ports.push(i)
        }
      }
    } else {
      const port = parseInt(trimmed)
      if (port && port > 0 && port <= 65535) {
        ports.push(port)
      }
    }
  }
  
  return [...new Set(ports)].sort((a, b) => a - b)
}

const onScanTypeChange = () => {
  if (scanType.value !== 'custom') {
    customPorts.value = ''
  }
}

const startScan = async () => {
  if (!targetIP.value.trim()) {
    ElMessage.warning('请输入目标IP地址')
    return
  }
  
  if (!validateIP(targetIP.value.trim())) {
    ElMessage.error('请输入有效的IP地址或域名')
    return
  }
  
  const ports = getPortRange()
  if (ports.length === 0) {
    ElMessage.error('请设置有效的端口范围')
    return
  }
  
  isScanning.value = true
  scanProgress.value = 0
  scanResults.value = []
  scanStartTime.value = Date.now()
  totalPorts.value = ports.length
  currentPort.value = 0
  
  try {
    for (let i = 0; i < ports.length; i++) {
      if (!isScanning.value) break
      
      const port = ports[i]
      currentPort.value = port
      scanStatus.value = `正在扫描端口 ${port}...`
      
      // 模拟端口扫描
      await new Promise(resolve => setTimeout(resolve, 50))
      
      // 模拟扫描结果
      const isOpen = Math.random() < 0.1 // 10% 概率开放
      const service = getServiceByPort(port)
      
      const result = {
        port: port,
        status: isOpen ? 'open' : 'closed',
        service: isOpen ? service : 'Unknown',
        protocol: 'TCP',
        responseTime: Math.floor(Math.random() * 100 + 10)
      }
      
      scanResults.value.push(result)
      scanProgress.value = ((i + 1) / ports.length) * 100
    }
    
    if (isScanning.value) {
      scanStatus.value = '扫描完成'
      scanProgress.value = 100
      
      // 添加到历史
      addToHistory()
      
      ElMessage.success(`扫描完成，发现 ${openPortsCount.value} 个开放端口`)
    }
    
  } catch (error) {
    ElMessage.error('扫描失败：' + error.message)
  } finally {
    isScanning.value = false
  }
}

const getServiceByPort = (port) => {
  const portMap = {
    21: 'FTP',
    22: 'SSH',
    23: 'Telnet',
    25: 'SMTP',
    53: 'DNS',
    80: 'HTTP',
    110: 'POP3',
    143: 'IMAP',
    443: 'HTTPS',
    993: 'IMAPS',
    995: 'POP3S',
    3389: 'RDP'
  }
  
  return portMap[port] || 'Unknown'
}

const stopScan = () => {
  isScanning.value = false
  ElMessage.info('扫描已停止')
}

const clearResults = () => {
  scanResults.value = []
  scanProgress.value = 0
  scanStatus.value = ''
  currentPort.value = 0
  totalPorts.value = 0
  ElMessage.info('结果已清空')
}

const addToHistory = () => {
  const historyItem = {
    ip: targetIP.value,
    totalPorts: totalPorts.value,
    openPorts: openPortsCount.value,
    date: new Date().toLocaleString('zh-CN')
  }
  
  scanHistory.value.unshift(historyItem)
  
  // 限制历史记录数量
  if (scanHistory.value.length > 20) {
    scanHistory.value = scanHistory.value.slice(0, 20)
  }
}

const loadFromHistory = (item) => {
  targetIP.value = item.ip
  ElMessage.success(`已加载：${item.ip}`)
}

const setPort = (port) => {
  scanType.value = 'custom'
  customPorts.value = port.toString()
  ElMessage.success(`已设置端口：${port}`)
}
</script>

<style scoped>
.port-scanner-tool {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
}

.tool-header {
  text-align: center;
  margin-bottom: 40px;
}

.tool-header h1 {
  font-size: 2.5rem;
  color: #333;
  margin-bottom: 10px;
}

.tool-header p {
  color: #666;
  font-size: 1.1rem;
}

.tool-container {
  margin-bottom: 40px;
}

.scanner-section,
.tools-section {
  background: white;
  border-radius: 12px;
  padding: 24px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
  border: 1px solid #f0f0f0;
  height: 100%;
}

.scanner-config,
.scan-progress,
.scan-results,
.scan-history {
  margin-bottom: 30px;
}

.scanner-config h3,
.scan-results h3,
.scan-history h3 {
  color: #333;
  margin-bottom: 20px;
  font-size: 1.3rem;
}

.config-inputs {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.input-group {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.input-group label {
  font-weight: 500;
  color: #666;
}

.scan-options {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 15px;
}

.option-group {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.option-group label {
  font-weight: 500;
  color: #666;
}

.scan-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.scan-progress h4 {
  color: #333;
  margin-bottom: 15px;
  font-size: 1.1rem;
}

.progress-info {
  display: flex;
  justify-content: space-between;
  margin-top: 10px;
  color: #666;
}

.results-summary {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 15px;
  margin-bottom: 30px;
}

.summary-item {
  background: #f8f9fa;
  border-radius: 8px;
  padding: 15px;
  text-align: center;
  border: 1px solid #e9ecef;
}

.summary-label {
  font-size: 0.9rem;
  color: #666;
  margin-bottom: 5px;
}

.summary-value {
  font-size: 1.2rem;
  font-weight: bold;
  color: #333;
}

.ports-table {
  background: #f8f9fa;
  border-radius: 8px;
  overflow: hidden;
  border: 1px solid #e9ecef;
}

.table-header {
  display: grid;
  grid-template-columns: 1fr 1fr 2fr 1fr 1fr;
  background: #667eea;
  color: white;
  font-weight: bold;
}

.header-cell {
  padding: 12px;
  text-align: center;
  border-right: 1px solid rgba(255, 255, 255, 0.2);
}

.header-cell:last-child {
  border-right: none;
}

.table-row {
  display: grid;
  grid-template-columns: 1fr 1fr 2fr 1fr 1fr;
  border-bottom: 1px solid #e9ecef;
}

.table-row:last-child {
  border-bottom: none;
}

.table-row.open {
  background: #f0f9ff;
}

.cell {
  padding: 12px;
  text-align: center;
  border-right: 1px solid #e9ecef;
  background: white;
}

.cell:last-child {
  border-right: none;
}

.table-row.open .cell {
  background: #f0f9ff;
}

.port-cell {
  font-weight: bold;
  color: #333;
}

.status-cell {
  font-weight: 500;
}

.service-cell {
  color: #666;
}

.protocol-cell {
  color: #666;
}

.time-cell {
  color: #666;
}

.history-list {
  max-height: 300px;
  overflow-y: auto;
}

.history-item {
  background: #f8f9fa;
  border-radius: 8px;
  padding: 15px;
  margin-bottom: 10px;
  cursor: pointer;
  transition: all 0.2s ease;
  border: 1px solid #e9ecef;
}

.history-item:hover {
  background: #e9ecef;
  transform: translateY(-1px);
}

.history-ip {
  font-size: 1rem;
  color: #333;
  margin-bottom: 8px;
  font-weight: 500;
}

.history-info {
  display: flex;
  gap: 15px;
  font-size: 0.9rem;
  color: #666;
}

.history-open {
  color: #28a745;
  font-weight: 500;
}

.history-time {
  color: #999;
}

.empty-history {
  text-align: center;
  color: #999;
  padding: 40px 0;
  font-style: italic;
}

.section-header {
  margin-bottom: 20px;
}

.section-header h3 {
  color: #333;
  margin: 0;
  font-size: 1.3rem;
}

.common-ports {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.port-item {
  display: flex;
  align-items: center;
  gap: 15px;
  background: #f8f9fa;
  border-radius: 8px;
  padding: 15px;
  cursor: pointer;
  transition: all 0.2s ease;
  border: 1px solid #e9ecef;
}

.port-item:hover {
  background: #e9ecef;
  transform: translateY(-2px);
}

.port-number {
  font-size: 1.2rem;
  font-weight: bold;
  color: #667eea;
  min-width: 50px;
}

.port-service {
  font-size: 1rem;
  font-weight: bold;
  color: #333;
  margin-bottom: 2px;
}

.port-description {
  font-size: 0.9rem;
  color: #666;
}

.help-section {
  margin-top: 20px;
}

.card-header {
  font-weight: bold;
  color: #333;
}

.help-content h4 {
  color: #333;
  margin: 20px 0 10px 0;
  font-size: 1.1rem;
}

.help-content ul {
  color: #666;
  padding-left: 20px;
  margin-bottom: 15px;
}

.help-content li {
  margin-bottom: 5px;
}

.warning {
  background: #fff3cd;
  padding: 15px;
  border-radius: 8px;
  border-left: 4px solid #ffc107;
  margin: 15px 0;
}

.warning p {
  margin: 5px 0;
  color: #856404;
}

@media (max-width: 768px) {
  .tool-header h1 {
    font-size: 2rem;
  }
  
  .scan-options {
    grid-template-columns: 1fr;
  }
  
  .scan-actions {
    flex-direction: column;
  }
  
  .results-summary {
    grid-template-columns: repeat(2, 1fr);
  }
  
  .table-header,
  .table-row {
    grid-template-columns: 1fr;
  }
  
  .header-cell,
  .cell {
    border-right: none;
    border-bottom: 1px solid #e9ecef;
  }
  
  .history-info {
    flex-direction: column;
    gap: 5px;
  }
}
</style>
